package com.studykun.client.util;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasBlurHandlers;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HasValue;

public class ValueChangeBehaviour<V, E extends HasValue<V> & HasChangeHandlers & HasFocusHandlers & HasBlurHandlers & Focusable> {
  private V oldValue_;
  private final E element_;
  private final Timer timer_;
  
  private ValueChangeBehaviour(
      final E element) {
    element_ = element;
    oldValue_ = element.getValue();
    element.addBlurHandler(new BlurHandler() {
      public void onBlur(BlurEvent event) {
        ValueChangeBehaviour.this.onBlur(event);
      }
    });
    element.addFocusHandler(new FocusHandler() {
      public void onFocus(FocusEvent event) {
        ValueChangeBehaviour.this.onFocus(event);
      }});
    timer_ = new Timer() {
      @Override
      public void run() {
        ValueChangeBehaviour.this.run();
      }
    };
  }
  
  public static <
    V,
    E extends HasValue<V> & HasChangeHandlers & HasFocusHandlers & HasBlurHandlers & Focusable>
  ValueChangeBehaviour<V, E> addTo(
      final E element) {
    final ValueChangeBehaviour<V, E> valueChangeBehaviour =
      new ValueChangeBehaviour<V, E>(element);
    return valueChangeBehaviour;
  }
  
  private void run() {
    final V newValue = element_.getValue();
    if (!oldValue_.equals(newValue)) {
      ValueChangeEvent.fire(element_, newValue);
      oldValue_ = newValue;
    }
  }
  
  private void onBlur(
      final BlurEvent event) {
    timer_.cancel();
  }
  protected void onFocus(
      final FocusEvent event) {
    timer_.scheduleRepeating(100);
  }
  
  public E getElement() {
    return element_;
  }
}
